﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FinancialCalculator.Module
{
    class TimeValueOfMoney
    {
        public double pv = 0;
        public double fv = 0;
        public double pmt = 0;
        public double iy = 0;
        public int n = 0;

        public TimeValueOfMoney() 
        {
            pv = 0;
            fv = 0;
            pmt = 0;
            iy = 0;
            n = 0;
        }
        public TimeValueOfMoney(double p, double f, double pmtx, double i, int nx)
        {
            pv = p;
            fv = f;
            pmt = pmtx;
            iy = i;
            n = nx;
        }

        public void setPV(double p) { pv = p; }
        public void setFV(double f) { fv = f; }
        public void setIY(double i) { iy = i; }
        public void setPMT(double p) { pmt = p; }
        public void setN(int j) { n = j; }
        public double getPV() { return pv; }
        public double getFV() { return fv; }
        public double getIY() { return iy; }
        public double getPMT() {return pmt; }
        public int getN() { return n; }
        public double calculate_FV()
        {
            double p = pv;
            double pmtx = pmt;
            double i = iy;
            int nx = n;
            double fv_value = 0;
            if (nx <= 0) return p; //if period = 0
            if (pmtx <= 0) //if no payments made after first payment
            {
                fv_value = 0 - p * Math.Pow((1 + i / 100), nx);
            }
            else
            {
                fv_value = p * Math.Pow((1 + i / 100), nx); //fv of pv after n periods
                for (int j = 1; j <= nx; j++) 
                {
                    fv_value += pmt * Math.Pow((1 + i), j);
                }
                fv_value *= -1;
            }
            return fv_value;
        }
        public double calculate_PV()
        {
            double f = fv;
            double pmtx = pmt;
            double i = iy;
            int nx = n;
            double pv_value = 0;
            if (nx <= 0) return f; //if period = 0
            if (pmtx <= 0) //if no payments made after first payment
            {
                pv_value = 0 - f / Math.Pow((1 + i / 100), nx);
            }
            else
            {
                for (int j = 1; j <= nx; j++)
                {
                    f -= pmt * Math.Pow((1 + i), j);
                }
                pv_value = 0 - f / Math.Pow((1 + i / 100), nx);
                pv_value *= -1;
            }
            return pv_value;
        }
        public double calculate_IY()
        {
            double p = pv;
            double f = fv;
            double pmtx = pmt;
            int nx = n;
            double i = 0;
            double j = 0;
            if (nx <= 0) return 0; //if period = 0
            if ((pmtx <= 0) && (nx <= 1)) //if no payments made after first payment
            {
                i = Math.Log(nx, -f / p) - 1;
            }
            else
            {
                //now we have to do the evaluated calculation
                if (nx == 2)
                {
                    j = -f / (p + (1 / nx) - 0.5);
                }
                else
                {
                    j = Math.Pow(-f / (p + 1 / n), (2 / n));
                }
                i = Math.Sqrt(j) - 1;
            }
            return i;
        }
        public double calculate_pmt()
        {
            double p = pv;
            double f = fv;
            double i = iy;
            int nx = n;
            double pmtx = 0;
            if (nx <= 0) return 0; //if period = 0
            if ((Math.Log(nx, -f / p) - 1) == i) //if no payments made after first payment
            {
                return 0;
            }
            else
            {
                double residual = -f - Math.Pow(1 + i, nx);
                double x = 1 + i;
                pmtx = residual / (Math.Pow(x, n) / n - Math.Pow(x, 2) / 2);
            }
            return pmtx;
        }
        public int calculate_n()
        {
            double p=pv;
            double f=fv;
            double i=iy;
            double pmtx = pmt;
            int period = 0;
            if (pmtx == 0)
            //if no payments made after first payment
            {
                if (-f == p) { return 0; }
                else
                {
                    return period = (int)(Math.Floor(Math.Log(-f / p, (1 + i))));
                }
            }
            else
            {
                if (Math.Abs(f) <= p*(1+i))
                {
                    return period = 1;
                }
                else if ((Math.Abs(f) <= p * Math.Pow((1 + i), 2) + pmtx)
                    && (Math.Abs(f)) > p * (i+1))
                {
                    return period = 2;
                }
                else if (Math.Abs(f) <= p * Math.Pow((1 + i), 3) + pmtx + pmtx * (1+i))
                {
                    return period = 3;
                }
                else
                {
                    double x = 1+i;
                    return period = (int)(Math.Floor(Math.Log(x, (f+x*x/2)/p)));
                }
            
            }

        }
        public void ResetTimeValueOfMoney()
        {
            pv = 0;
            fv = 0;
            pmt = 0;
            iy = 0;
            n = 0;
        }
    }
}
